package com.avcdata.validate;

import com.avcdata.core.Result;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@Component
@Aspect
@Order(2)
public class ValidateAspectHandel {
  @Autowired
  Gson gson;

  private static Logger log = LoggerFactory.getLogger(ValidateAspectHandel.class);
  /**
   * 使用AOP对使用了ValidateGroup的方法进行代理校验
   * @throws Throwable
   */

  @Around("@annotation(com.avcdata.validate.ValidateGroup)")
  public Object validateAround(ProceedingJoinPoint joinPoint) throws Throwable  {
    boolean flag = false ;
    Map<String,Object> map=new HashMap<>();
    ValidateGroup an = null;
    Object[] args;
    Method method = null;
    Object target;
    String methodName;
    try{
      methodName = joinPoint.getSignature().getName();
      target = joinPoint.getTarget();
      method = getMethodByClassAndName(target.getClass(), methodName);//得到拦截的方法
      args = joinPoint.getArgs();	//方法的参数
      assert method != null;
      an = method.getAnnotation(ValidateGroup.class);//得到方法上的注解
      if(an==null){
        flag=true;
      }else{
        map = validateFiled(an.fileds() , args);
      }
    }catch(Exception e){
      e.printStackTrace();
    }
    String status=(String) map.get("status");
    if("0".equals(status)){
      flag=true;
    }
    if(flag){
      log.info("属性验证通过");
      return joinPoint.proceed();
    }else{	//这里使用了Spring MVC ，所有返回值应该为Strng或ModelAndView
      log.info("属性验证未通过");
      assert method != null;
      Class<?> returnType = method.getReturnType();	//得到方法返回值类型
      if(returnType == ModelAndView.class){
        ModelAndView mv=new ModelAndView();//返回错误页面
        assert an != null;
        if(!StringUtils.isEmpty(an.view())){
          mv.setViewName(an.view());
        }
        mv.addAllObjects(map);
        return mv;

      }else if(returnType==Map.class){	//当使用Ajax的时候 可能会出现这种情况
        return map ;
      }else if(returnType == Result.class){
        return new Result<>(null, false, map.get("message").toString());
      }else{
        return null;
      }
    }
  }
  /**
   * 验证参数是否合法
   */
  private Map<String,Object> validateFiled(ValidateFiled[] valiedatefiles, Object[] args) throws Exception{
    Map<String,Object> map=new HashMap<String,Object>();
    map.put("status", "0");
    for (ValidateFiled validateFiled : valiedatefiles){
      StringBuffer message=new StringBuffer();
      String showName=validateFiled.showName();
      String fileName=validateFiled.filedName();
      message.append("".equals(showName)?fileName:showName);
      Object arg = null;
      if(StringUtils.isEmpty(fileName)){
        arg = args[validateFiled.index()];
      }else{
        arg = getFieldByObjectAndFileName(args[validateFiled.index()],fileName);
      }
      if(validateFiled.notNull()){//判断参数是否为空
        if(arg == null|| StringUtils.isEmpty(String.valueOf(arg))){
          map.put("status", "1");
          map.put("message", message.append(" 不能为空!"));
          return map;
        }
      }else{//如果该参数能够为空，并且当参数为空时，就不用判断后面的了 ，直接返回true
        if(arg == null|| StringUtils.isEmpty(String.valueOf(arg))){
          continue;
        }
      }

      if(!StringUtils.isEmpty(validateFiled.regStr())){//判断正则
        if(!(String.valueOf(arg)).matches(validateFiled.regStr())){
          map.put("status", "1");
          map.put("message", message.append(" 格式不正确"));
          return map;
        }
      }

      if(validateFiled.maxLen() > 0){//判断字符串最大长度
        if(((String)arg).length() > validateFiled.maxLen()){
          map.put("status", "1");
          map.put("message", message.append(" 不能超过").append(validateFiled.maxLen()).append("个字符!"));
          return map;
        }
      }
      if(validateFiled.minLen() > 0){//判断字符串最小长度
        if(((String)arg).length() < validateFiled.minLen()){
          map.put("status", "1");
          map.put("message", message.append(" 不能少于").append(validateFiled.minLen()).append("个字符!"));
          return map;
        }
      }

      if(validateFiled.maxVal() != -1){//判断数值最大值
        if( (Integer)arg > validateFiled.maxVal()){
          map.put("status", "1");
          map.put("message", message.append(" 数值不能大于").append(validateFiled.maxVal()));
          return map;
        }
      }

      if(validateFiled.minVal() != -1){//判断数值最小值
        if((Integer) arg < validateFiled.minVal()){
          map.put("status", "1");
          map.put("message", message.append(" 数值不能小于").append(validateFiled.minVal()));
          return map;
        }
      }

      if(!StringUtils.isEmpty(validateFiled.values())){//判断属性是否有固定值
        boolean flag=false;
        //获取分隔符
        String separator=validateFiled.separator();
        //属性的值
        String argValue=String.valueOf(arg);
        String values=validateFiled.values();
        if(!StringUtils.isEmpty(separator)){//可以为多个值
          String[] valueArray=values.split(separator);
          if(valueArray!=null&&valueArray.length>0){
            for(String val:valueArray){
              if(val.equals(argValue)){
                flag=true;
                break;
              }
            }
          }
        }else{
          if(!argValue.equals(values)){//只允许为一个值
            map.put("status", "1");
            map.put("message", message.append(" 的值只能是").append(values));
            return map;
          }else{
            flag=true;
          }
        }
        if(!flag){
          map.put("status", "1");
          map.put("message", message.append(" 的值不在").append(values).append("内"));
          return map;
        }
      }
    }
    return map;
  }
  /**
   * 根据对象和属性名得到 属性值
   * @throws NoSuchFieldException
   */
  private Object getFieldByObjectAndFileName(Object targetObj, String fileName) throws Exception{
    Object arg = targetObj ;
    arg=getField(arg,fileName);
    return arg ;
  }
  /**
   * 根据类和方法名得到方法
   */
  @SuppressWarnings("rawtypes")
  private Method getMethodByClassAndName(Class c, String methodName){
    Method[] methods = c.getDeclaredMethods();
    for (Method method : methods) {
      if(method.getName().equals(methodName)){
        return method ;
      }
    }
    return null;
  }
  /**
   * 获取Field
   * @param fileName
   * @return
   */
  private Object getField(Object object,String fileName) throws Exception{
    Object obj=null;
    Class<?> clazz = object.getClass() ;
    try {
      PropertyDescriptor pd = new PropertyDescriptor(fileName, clazz);
      Method getMethod=pd.getReadMethod();//获取get方法
      obj=getMethod.invoke(object);
      log.info(clazz+":"+fileName+":"+obj);
    } catch (IntrospectionException e) {
      log.error(clazz+" 没有属性："+fileName);
    }

    return obj;
  }

  private void writeToResponse(HttpServletRequest request, HttpServletResponse response,
      Map<String, Object> map) {
    // 判断是否是ajax请求
    String type = request.getHeader("X-Requested-With");
    PrintWriter out = null;
    response.reset();
    try {
      // 判断是否异步请求
      /**if (StringUtils.isNotEmpty(type) && "XMLHttpRequest".endsWith(type)) {

       } else {
       out = response.getWriter();
       out.print(value);
       }*/
      response.setCharacterEncoding("UTF-8");
      response.setContentType("application/json; charset=utf-8");
      out = response.getWriter();
      out.print(gson.toJson(map));
    } catch (IOException e) {
      e.printStackTrace();
    }finally{
      if(out!=null){
        out.flush();
        out.close();
      }
    }
  }
}

